{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "3161905b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from utils.preprocessing import DataLoader\n",
    "import gurobipy as gp\n",
    "from gurobipy import *\n",
    "import math"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e84b7648",
   "metadata": {},
   "source": [
    "# 数据读取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "0a5f5357",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_loader = DataLoader('data/Data A-Crew.csv', 'data/Data A-Flight.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "7def7bd4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counting times...(0/206)\n",
      "Counting times...(100/206)\n",
      "Counting times...(200/206)\n",
      "## Loading C\n",
      "## C loaded\n",
      "## Loading AP\n",
      "## AP loaded\n",
      "## Loading Base\n",
      "## Base loaded\n",
      "## Loading F\n",
      "## F loaded\n",
      "## Loading FF\n",
      "Loading data... (10000/42436)\n",
      "Loading data... (20000/42436)\n",
      "Loading data... (30000/42436)\n",
      "Loading data... (40000/42436)\n",
      "## FF loaded\n",
      "## Loading FF1\n",
      "Loading data... (10000/42436)\n",
      "Loading data... (20000/42436)\n",
      "Loading data... (30000/42436)\n",
      "Loading data... (40000/42436)\n",
      "## FF1 loaded\n",
      "## Loading FF2\n",
      "Loading data... (10000/42436)\n",
      "Loading data... (20000/42436)\n",
      "Loading data... (30000/42436)\n",
      "Loading data... (40000/42436)\n",
      "## FF2 loaded\n",
      "Counting times...(0/206)\n",
      "Counting times...(100/206)\n",
      "Counting times...(200/206)\n"
     ]
    }
   ],
   "source": [
    "data_loader.dump_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "id": "8d26649a",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_loader_a = DataLoader('data/Data A-Crew.csv', 'data/Data A-Flight.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "416bc926",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counting times...(0/64)\n",
      "## Loading C\n",
      "## C loaded\n",
      "## Loading AP\n",
      "## AP loaded\n",
      "## Loading Base\n",
      "## Base loaded\n",
      "## Loading F\n",
      "## F loaded\n",
      "## Loading FF\n",
      "## FF loaded\n",
      "## Loading FF1\n",
      "## FF1 loaded\n",
      "## Loading FF2\n",
      "## FF2 loaded\n",
      "Counting times...(0/64)\n"
     ]
    }
   ],
   "source": [
    "data_loader_a.dump_data(cropped_date=(11, 15))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b13e0141",
   "metadata": {},
   "source": [
    "# 模型建立与求解"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b4c1283",
   "metadata": {},
   "source": [
    "## 第一阶段"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5e635ee",
   "metadata": {},
   "source": [
    "### 优化目标①"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "id": "6c1a0539",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gurobi Optimizer version 9.1.2 build v9.1.2rc0 (win64)\n",
      "Thread count: 8 physical cores, 16 logical processors, using up to 16 threads\n",
      "Optimize a model with 599548 rows, 356224 columns and 2673445 nonzeros\n",
      "Model fingerprint: 0x6d2456e7\n",
      "Variable types: 0 continuous, 356224 integer (356224 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 1e+04]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+00]\n",
      "  RHS range        [1e+00, 1e+04]\n",
      "Found heuristic solution: objective 0.0000000\n",
      "Presolve removed 583246 rows and 329634 columns\n",
      "Presolve time: 3.97s\n",
      "Presolved: 16302 rows, 26590 columns, 120878 nonzeros\n",
      "Variable types: 0 continuous, 26590 integer (26590 binary)\n",
      "\n",
      "Deterministic concurrent LP optimizer: primal and dual simplex\n",
      "Showing first log only...\n",
      "\n",
      "\n",
      "Root simplex log...\n",
      "\n",
      "Iteration    Objective       Primal Inf.    Dual Inf.      Time\n",
      "    8067   -9.1492640e+00   0.000000e+00   4.673035e+04      5s\n",
      "   29239   -2.6859175e+01   0.000000e+00   6.889102e+04     10s\n",
      "   36582   -2.9184311e+01   0.000000e+00   6.858104e+03     15s\n",
      "   45124   -4.2635606e+01   0.000000e+00   6.333624e+04     20s\n",
      "Concurrent spin time: 2.70s\n",
      "\n",
      "Solved with dual simplex\n",
      "\n",
      "Root relaxation: objective -6.400000e+01, 29980 iterations, 16.69 seconds\n",
      "Total elapsed time = 26.03s\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0  -64.00000    0   86    0.00000  -64.00000      -     -   26s\n",
      "H    0     0                     -64.0000000  -64.00000  0.00%     -   26s\n",
      "     0     0  -64.00000    0   86  -64.00000  -64.00000  0.00%     -   26s\n",
      "\n",
      "Explored 1 nodes (70604 simplex iterations) in 26.82 seconds\n",
      "Thread count was 16 (of 16 available processors)\n",
      "\n",
      "Solution count 2: -64 0 \n",
      "No other solutions better than -64\n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective -6.400000000000e+01, best bound -6.400000000000e+01, gap 0.0000%\n"
     ]
    }
   ],
   "source": [
    "MaxTAFB = 14400 / 15 * 5\n",
    "\n",
    "m=gp.Model('m1')\n",
    "\n",
    "z=m.addVars(data_loader_a.F,vtype=gp.GRB.BINARY,name='z')\n",
    "x_ikdh=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='x_dh')\n",
    "x_ikfo=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='x_fo')\n",
    "x_ikcap=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='x_cap')\n",
    "\n",
    "r_iksta=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='r_iksta')\n",
    "r_jkfin=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='r_jkfin')\n",
    "d_iksta=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='d_iksta')\n",
    "d_jkfin=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='d_jkfin')\n",
    "p_iksta=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='p_iksta')\n",
    "p_jkfin=m.addVars(data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='p_jkfin')\n",
    "\n",
    "y_ijk=m.addVars(data_loader_a.F,data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='y_ijk')\n",
    "v_ijk=m.addVars(data_loader_a.F,data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='v_ijk')\n",
    "w_ijk=m.addVars(data_loader_a.F,data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='w_ijk')\n",
    "u_ijk=m.addVars(data_loader_a.F,data_loader_a.F,data_loader_a.C,vtype=gp.GRB.BINARY,name='u_ijk')\n",
    "\n",
    "# a1=m.addVar(1,vtype=gp.GRB.INTEGER,name='a1')\n",
    "# a2=m.addVar(2,vtype=gp.GRB.INTEGER,name='a2')\n",
    "\n",
    "# a3=m.addVar(3,vtype=gp.GRB.INTEGER,name='a3')\n",
    "# a4=m.addVar(4,vtype=gp.GRB.INTEGER,name='a4')\n",
    "\n",
    "\n",
    "m.ModelSense=GRB.MINIMIZE\n",
    "\n",
    "m.setObjective(-z.sum())\n",
    "\n",
    "\n",
    "# m.setObjective(gp.quicksum(gp.quicksum(data_loader_a.DCost[k]*(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) \n",
    "#                                                                - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]))/60\n",
    "#                                                            for k in data_loader_a.C) for t in data_loader_a.Dates ))\n",
    "# m.setObjective(gp.quicksum(gp.quicksum(data_loader_a.PCost[k]*(u_ijk[i,j,k]*data_loader_a.arrivetime[j] - u_ijk[i,j,k]*data_loader_a.leavetime[i]) for i in data_loader_a.FD[t] for j in data_loader_a.FD[t])/60\n",
    "#                                                            for k in data_loader_a.C for t in data_loader_a.Dates ))\n",
    "# m.setObjectiveN(x_ikdh.sum(), index=2, priority=8)\n",
    "\n",
    "\n",
    "# m.setObjectiveN(a1-a2, index=3, priority=7)\n",
    "# m.setObjectiveN(a3-a4, index=4, priority=6)\n",
    "# m.setObjectiveN(gp.quicksum(x_ikfo[i,k] for i in data_loader_a.F for k in data_loader_a.C2), index=5, priority=5)\n",
    "\n",
    "# m.setObjectiveN(-z.sum(),index = 0,weight =0.8)\n",
    "# m.setObjectiveN(x_ikdh.sum(),index=1,weight=0.2)\n",
    "# m.setObjectiveN(gp.quicksum(x_ikfo[i,k] for i in data_loader_a.F for k in data_loader_a.C2),index=2,weight=0.05)\n",
    "\n",
    "\n",
    "M=10000\n",
    "#对X的约束\n",
    "m.addConstrs(x_ikfo[i,k]==0 for i in data_loader_a.F for k in data_loader_a.C1 )\n",
    "m.addConstrs(x_ikcap[i,k]==0 for i in data_loader_a.F for k in data_loader_a.C3 )\n",
    "m.addConstrs(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]<=1 for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "#对Z的约束\n",
    "m.addConstrs(gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for k in data_loader_a.C)<=M*(z[i]) for i in data_loader_a.F)\n",
    "m.addConstrs(x_ikcap.sum(i,'*')== z[i] for i in data_loader_a.F )\n",
    "m.addConstrs(x_ikfo.sum(i,'*')== z[i] for i in data_loader_a.F )\n",
    "m.addConstrs(M*z[j]>=gp.quicksum(x_ikcap[j,k]+x_ikfo[j,k]+x_ikdh[j,k] for k in data_loader_a.C) for j in data_loader_a.F)\n",
    "\n",
    "#对Y的约束\n",
    "m.addConstrs(y_ijk[i,j,k]==0 for i,j in data_loader_a.FF for k in data_loader_a.C)\n",
    "#m.addConstrs(gp.quicksum(y_ijk[i,j,k] for j in F)<=x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in F for k in C)\n",
    "#m.addConstrs(gp.quicksum(y_ijk[j,i,k] for j in F)<=x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in F for k in C)\n",
    "\n",
    "#对roaster周期的约束\n",
    "m.addConstrs(r_jkfin[j,k]== 0 for j in data_loader_a.nonF_arrive_base[0] for k in data_loader_a.C)\n",
    "m.addConstrs(r_iksta[i,k]== 0 for i in data_loader_a.nonF_leave_base[0] for k in data_loader_a.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(r_iksta[i,k] for i in data_loader_a.F_leave_base[0] )<=1  for k in data_loader_a.C)\n",
    "m.addConstrs(gp.quicksum(r_jkfin[j,k] for j in data_loader_a.F_arrive_base[0] )-gp.quicksum(r_iksta[i,k] for i in data_loader_a.F_leave_base[0] ) == 0 for k in data_loader_a.C)\n",
    "\n",
    "#第一问中航班对应周期的约束\n",
    "m.addConstrs(1-(y_ijk.sum(i,'*',k)+r_iksta[i,k]+r_jkfin[i,k])<=M*(1-(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])) for i in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs(y_ijk.sum(i,'*',k)+r_jkfin[i,k]-(y_ijk.sum('*',i,k)+r_iksta[i,k]) == 0 for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "m.addConstrs(y_ijk.sum(i,'*',k)+r_jkfin[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]  for i in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs(y_ijk.sum('*',i,k)+r_iksta[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]  for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "#第二问\n",
    "#对V的约束\n",
    "m.addConstrs(v_ijk[i,j,k]==0 for i,j in data_loader_a.FF1 for k in data_loader_a.C)\n",
    "m.addConstrs(v_ijk[i,j,k] <= y_ijk[i,j,k] for i in data_loader_a.F for j in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "\n",
    "#对duty执勤的约束\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a.FD[t]) - gp.quicksum(d_jkfin[i,k] for i in data_loader_a.FD[t]) == 0 for i in data_loader_a.F for k in data_loader_a.C for t in data_loader_a.Dates)\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a.FD[t])   <= gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a.FD[t]) for i in data_loader_a.F for k in data_loader_a.C for t in data_loader_a.Dates)\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a.FD[t])*M >= gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a.FD[t]) for k in data_loader_a.C for t in data_loader_a.Dates)\n",
    "\n",
    "#m.addConstrs(d_iksta[i,k] for i in data_loader_a.FD[t]  <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a.FD[t] for k in data_loader_a.C for t in data_loader_a.Dates)\n",
    "\n",
    "#第二问中航班对应执勤，执勤对应周期的约束\n",
    "m.addConstrs((v_ijk.sum(i,'*',k)+ r_jkfin[i,k] ==  d_jkfin[i,k]) for i in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs((v_ijk.sum('*',i,k)+ r_iksta[i,k] ==  d_iksta[i,k]) for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "#m.addConstrs((d_jkfin[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])  for i in data_loader_a.F for k in data_loader_a.C)\n",
    "#m.addConstrs((d_iksta[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])  for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "#第二问中其余约束\n",
    "m.addConstrs(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) <= 720 for k in data_loader_a.C for t in data_loader_a.Dates )\n",
    "m.addConstrs(gp.quicksum((x_ikcap[i,k]+x_ikfo[i,k])*(data_loader_a.leavetime[i]-data_loader_a.arrivetime[i]) for i in data_loader_a.FD[t]) <= 600 for k in data_loader_a.C for t in data_loader_a.Dates )\n",
    "#m.addConstrs(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) >= 0 for k in data_loader_a.C for t in data_loader_a.Dates )\n",
    "\n",
    "\n",
    "#m.addConstr(z.sum('*')==206)\n",
    "# m.addConstr(gp.quicksum(gp.quicksum(data_loader_a.DCost[k]*(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) \n",
    "#                     - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]))\n",
    "#                 for k in data_loader_a.C) for t in data_loader_a.Dates )==[1324573-100000,1324573+100000])\n",
    "#对执勤时长平衡的约束（辅助目标）\n",
    "# m.addConstrs(a1>=(gp.quicksum(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates) - gp.quicksum(gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates)) for k in data_loader_a.C)\n",
    "# m.addConstrs(a2<=(gp.quicksum(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates) - gp.quicksum(gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates)) for k in data_loader_a.C)\n",
    "         \n",
    "#第三问\n",
    "#对W的约束\n",
    "m.addConstrs(w_ijk[i,j,k]==0 for i,j in data_loader_a.FF2 for k in data_loader_a.C)\n",
    "m.addConstrs(w_ijk[i,j,k] <= v_ijk[i,j,k] for i in data_loader_a.F for j in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "\n",
    "\n",
    "#对U的约束\n",
    "m.addConstrs(r_jkfin[i,k] <=gp.quicksum(u_ijk[j,i,k] for j in data_loader_a.F) for i in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs(r_iksta[i,k] <=gp.quicksum(u_ijk[i,j,k] for j in data_loader_a.F) for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(u_ijk[j,i,k] for j in data_loader_a.F) <= d_jkfin[i,k] for i in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k] for j in data_loader_a.F) <= d_iksta[i,k] for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k] for j in data_loader_a.F)-(r_iksta[i,k] + gp.quicksum(w_ijk[j,i,k] for j in data_loader_a.F)) == 0 for i in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[j,i,k] for j in data_loader_a.F)-(r_jkfin[i,k] + gp.quicksum(w_ijk[i,j,k] for j in data_loader_a.F))== 0 for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "\n",
    "m.addConstrs(u_ijk[i,j,k]*(data_loader_a.leavedate[j] - data_loader_a.leavedate[i] )<= 4 for i in data_loader_a.F for j in data_loader_a.F for k in data_loader_a.C)\n",
    "#m.addConstrs(w_ijk[i,j,k]*(data_loader_a.leavedate[j] - data_loader_a.leavedate[i] )>= 2 for i in data_loader_a.F for j in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k]*(data_loader_a.arrivetime[j] - data_loader_a.leavetime[i])for i in data_loader_a.F for j in data_loader_a.F )<= MaxTAFB for k in data_loader_a.C)       \n",
    "m.addConstrs(u_ijk[i,j,k]==0 for i,j in data_loader_a.FF for k in data_loader_a.C)\n",
    "\n",
    "#对执勤时长平衡的约束（辅助目标）\n",
    "# m.addConstrs(a3>=(gp.quicksum(gp.quicksum(v_ijk[i,j,k]*data_loader_a.arrivetime[j] - v_ijk[i,j,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t] for j in data_loader_a.FD[t]) for t in data_loader_a.Dates )) for k in data_loader_a.C)\n",
    "# m.addConstrs(a4<=(gp.quicksum(gp.quicksum(v_ijk[i,j,k]*data_loader_a.arrivetime[j] - v_ijk[i,j,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t] for j in data_loader_a.FD[t]) for t in data_loader_a.Dates )) for k in data_loader_a.C)\n",
    "\n",
    "# m.addConstr(z.sum()==64)\n",
    "# m.addConstr(gp.quicksum(gp.quicksum(data_loader_a.DCost[k]*(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) \n",
    "#                                                           - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]))/60\n",
    "#                                                           for k in data_loader_a.C) for t in data_loader_a.Dates) == 175316)\n",
    "\n",
    "m.update()\n",
    "m.optimize()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "id": "551ba8aa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0: 1520\n",
      "1: 1660\n",
      "2: 4575\n",
      "3: 3140\n",
      "4: 4565\n",
      "5: 4580\n",
      "6: 4355\n",
      "7: 1660\n",
      "8: 3200\n",
      "9: 4495\n",
      "10: 4355\n",
      "11: 1695\n",
      "12: 4565\n",
      "13: 1660\n",
      "14: 1980\n",
      "15: 3140\n",
      "16: 3100\n",
      "17: 1660\n",
      "18: 1760\n",
      "19: 255\n",
      "20: 1520\n"
     ]
    }
   ],
   "source": [
    "for k in data_loader_a.C:\n",
    "    sum1 = 0\n",
    "    for i in data_loader_a.F:\n",
    "        for j in data_loader_a.F:\n",
    "            if u_ijk[i,j,k].x > 0.9:\n",
    "                sum1 += data_loader_a.arrivetime[j] - data_loader_a.leavetime[i]\n",
    "    print(str(k)+\": \"+str(sum1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "a0eac7be",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 20,\n",
       " 1: 20,\n",
       " 2: 20,\n",
       " 3: 20,\n",
       " 4: 20,\n",
       " 5: 20,\n",
       " 6: 20,\n",
       " 7: 20,\n",
       " 8: 20,\n",
       " 9: 20,\n",
       " 10: 20,\n",
       " 11: 20,\n",
       " 12: 20,\n",
       " 13: 20,\n",
       " 14: 20,\n",
       " 15: 20,\n",
       " 16: 20,\n",
       " 17: 20,\n",
       " 18: 20,\n",
       " 19: 20,\n",
       " 20: 20}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_loader_a.PCost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "5b9014b3",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'A0002': [2],\n",
       " 'A0018': [2],\n",
       " 'A0008': [2],\n",
       " 'A0014': [2],\n",
       " 'A0017': [3],\n",
       " 'A0015': [1, 2],\n",
       " 'A0004': [3],\n",
       " 'A0016': [3],\n",
       " 'A0006': [4],\n",
       " 'A0007': [4],\n",
       " 'A0011': [4],\n",
       " 'A0005': [4],\n",
       " 'A0013': [4],\n",
       " 'A0020': [1],\n",
       " 'A0003': [4],\n",
       " 'A0012': [2],\n",
       " 'A0010': [4],\n",
       " 'A0009': [3],\n",
       " 'A0001': [2],\n",
       " 'A0021': [2],\n",
       " 'A0019': [2]}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "loop_dic = {}\n",
    "for i in data_loader_a.F:\n",
    "    for j in data_loader_a.F:\n",
    "        for k in data_loader_a.C:\n",
    "            if u_ijk[i,j,k].x>0.9:\n",
    "                if data_loader_a.C_dic[k] in loop_dic.keys():\n",
    "                    loop_dic[data_loader_a.C_dic[k]].append(data_loader_a.leavedate[j]-data_loader_a.leavedate[i]+1)\n",
    "                else:\n",
    "                    loop_dic[data_loader_a.C_dic[k]]=[data_loader_a.leavedate[j]-data_loader_a.leavedate[i]+1]\n",
    "loop_dic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7a4e333f",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "19813.33333333334"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum = 0\n",
    "for i in data_loader_a.F:\n",
    "    for j in data_loader_a.F:\n",
    "        for k in data_loader_a.C:\n",
    "            sum+=data_loader_a.PCost[k]*(u_ijk[i,j,k].x*data_loader_a.arrivetime[j] - u_ijk[i,j,k].x*data_loader_a.leavetime[i])/60\n",
    "sum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "96c74ed7",
   "metadata": {},
   "outputs": [],
   "source": [
    "results_dic = {'em_no':[], 'fl_no':[], 'cls':[]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "id": "724d98de",
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in data_loader_a.F:\n",
    "    for k in data_loader_a.C:\n",
    "        if x_ikcap[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(1)\n",
    "        if x_ikfo[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(2)\n",
    "        if x_ikdh[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "0d9d7163",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A0002出发于NKX乘坐FA680/11到达PGX\n",
      "A0008出发于NKX乘坐FA680/11到达PGX\n",
      "A0014出发于NKX乘坐FA680/11到达PGX\n",
      "A0018出发于NKX乘坐FA680/11到达PGX\n",
      "A0017出发于NKX乘坐FA680/12到达PGX\n",
      "A0004出发于NKX乘坐FA812/11到达PDK\n",
      "A0006出发于NKX乘坐FA812/12到达PDK\n",
      "A0016出发于NKX乘坐FA812/12到达PDK\n",
      "A0007出发于NKX乘坐FA854/11到达CTH\n",
      "A0011出发于NKX乘坐FA854/11到达CTH\n",
      "A0005出发于NKX乘坐FA854/12到达CTH\n",
      "A0013出发于NKX乘坐FA854/12到达CTH\n",
      "A0020出发于NKX乘坐FA864/11到达PXB\n",
      "A0003出发于NKX乘坐FA864/12到达PXB\n",
      "A0012出发于NKX乘坐FA864/14到达PXB\n",
      "A0010出发于NKX乘坐FA872/12到达PLM\n",
      "A0001出发于NKX乘坐FA884/11到达XGS\n",
      "A0009出发于NKX乘坐FA884/11到达XGS\n",
      "A0015出发于NKX乘坐FA884/11到达XGS\n",
      "A0021出发于NKX乘坐FA884/11到达XGS\n",
      "A0019出发于NKX乘坐FA884/14到达XGS\n"
     ]
    }
   ],
   "source": [
    "for i in data_loader_a.F:\n",
    "    for k in data_loader_a.C:\n",
    "        if r_iksta[i,k].x > 0.9:\n",
    "            print(str(data_loader_a.C_dic[k])+\"出发于\"+str(data_loader_a.AP_dic[data_loader_a.F_ap_dpt_dic[i]])+\"乘坐\"+str(data_loader_a.F_dic[i])+\"到达\"+str(data_loader_a.AP_dic[data_loader_a.F_ap_arr_dic[i]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "id": "960fb76a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A0002乘坐FA3/12\n",
      "A0018乘坐FA3/12\n",
      "A0008乘坐FA681/12\n",
      "A0014乘坐FA681/12\n",
      "A0017乘坐FA681/14\n",
      "A0015乘坐FA681/15\n",
      "A0004乘坐FA813/13\n",
      "A0016乘坐FA813/14\n",
      "A0006乘坐FA813/15\n",
      "A0007乘坐FA855/14\n",
      "A0011乘坐FA855/14\n",
      "A0005乘坐FA855/15\n",
      "A0013乘坐FA855/15\n",
      "A0020乘坐FA865/11\n",
      "A0003乘坐FA865/15\n",
      "A0012乘坐FA865/15\n",
      "A0010乘坐FA873/15\n",
      "A0009乘坐FA885/13\n",
      "A0019乘坐FA885/15\n",
      "A0001乘坐FA891/12\n",
      "A0021乘坐FA891/12\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{1: 1,\n",
       " 17: 1,\n",
       " 7: 8,\n",
       " 13: 8,\n",
       " 16: 10,\n",
       " 14: 11,\n",
       " 3: 19,\n",
       " 15: 20,\n",
       " 5: 21,\n",
       " 6: 30,\n",
       " 10: 30,\n",
       " 4: 31,\n",
       " 12: 31,\n",
       " 19: 37,\n",
       " 2: 41,\n",
       " 11: 41,\n",
       " 9: 49,\n",
       " 8: 57,\n",
       " 18: 59,\n",
       " 0: 61,\n",
       " 20: 61}"
      ]
     },
     "execution_count": 94,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temp_leave = {}\n",
    "for i in data_loader_a.F:\n",
    "    for k in data_loader_a.C:\n",
    "        if r_jkfin[i,k].x > 0.9:\n",
    "            print(str(data_loader_a.C_dic[k])+\"乘坐\"+str(data_loader_a.F_dic[i]))\n",
    "            temp_leave[k] = i\n",
    "temp_leave"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "id": "43e3aebf",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counting times...(0/72)\n",
      "## Loading C\n",
      "## C loaded\n",
      "## Loading AP\n",
      "## AP loaded\n",
      "## Loading Base\n",
      "## Base loaded\n",
      "## Loading F\n",
      "## F loaded\n",
      "## Loading FF\n",
      "## FF loaded\n",
      "## Loading FF1\n",
      "## FF1 loaded\n",
      "## Loading FF2\n",
      "## FF2 loaded\n",
      "Counting times...(0/72)\n"
     ]
    }
   ],
   "source": [
    "data_loader_a2 = DataLoader('data/Data A-Crew.csv', 'data/Data A-Flight.csv')\n",
    "data_loader_a2.dump_data(cropped_date=(16, 20))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "446fcf9c",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 'FA680/16',\n",
       " 1: 'FA680/17',\n",
       " 2: 'FA680/18',\n",
       " 3: 'FA680/19',\n",
       " 4: 'FA680/20',\n",
       " 5: 'FA681/16',\n",
       " 6: 'FA681/17',\n",
       " 7: 'FA681/18',\n",
       " 8: 'FA681/19',\n",
       " 9: 'FA681/20',\n",
       " 10: 'FA812/16',\n",
       " 11: 'FA812/17',\n",
       " 12: 'FA812/18',\n",
       " 13: 'FA812/19',\n",
       " 14: 'FA812/20',\n",
       " 15: 'FA813/16',\n",
       " 16: 'FA813/17',\n",
       " 17: 'FA813/18',\n",
       " 18: 'FA813/19',\n",
       " 19: 'FA813/20',\n",
       " 20: 'FA854/16',\n",
       " 21: 'FA854/17',\n",
       " 22: 'FA854/18',\n",
       " 23: 'FA854/19',\n",
       " 24: 'FA854/20',\n",
       " 25: 'FA855/16',\n",
       " 26: 'FA855/17',\n",
       " 27: 'FA855/18',\n",
       " 28: 'FA855/19',\n",
       " 29: 'FA855/20',\n",
       " 30: 'FA864/16',\n",
       " 31: 'FA864/17',\n",
       " 32: 'FA864/18',\n",
       " 33: 'FA864/19',\n",
       " 34: 'FA864/20',\n",
       " 35: 'FA865/16',\n",
       " 36: 'FA865/17',\n",
       " 37: 'FA865/18',\n",
       " 38: 'FA865/19',\n",
       " 39: 'FA865/20',\n",
       " 40: 'FA872/16',\n",
       " 41: 'FA872/17',\n",
       " 42: 'FA872/18',\n",
       " 43: 'FA872/19',\n",
       " 44: 'FA872/20',\n",
       " 45: 'FA873/16',\n",
       " 46: 'FA873/17',\n",
       " 47: 'FA873/18',\n",
       " 48: 'FA873/19',\n",
       " 49: 'FA873/20',\n",
       " 50: 'FA884/16',\n",
       " 51: 'FA884/17',\n",
       " 52: 'FA884/18',\n",
       " 53: 'FA884/19',\n",
       " 54: 'FA884/20',\n",
       " 55: 'FA885/16',\n",
       " 56: 'FA885/17',\n",
       " 57: 'FA885/18',\n",
       " 58: 'FA885/19',\n",
       " 59: 'FA885/20',\n",
       " 60: 'FA888/18',\n",
       " 61: 'FA889/18',\n",
       " 62: 'FA890/16',\n",
       " 63: 'FA890/17',\n",
       " 64: 'FA890/18',\n",
       " 65: 'FA890/19',\n",
       " 66: 'FA890/20',\n",
       " 67: 'FA891/16',\n",
       " 68: 'FA891/17',\n",
       " 69: 'FA891/18',\n",
       " 70: 'FA891/19',\n",
       " 71: 'FA891/20'}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_loader_a2.F_dic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "id": "86eed0fd",
   "metadata": {},
   "outputs": [],
   "source": [
    "for k in data_loader_a2.C:\n",
    "    for key, value in data_loader_a2.F_dic.items():\n",
    "        if value == temp_leave[k]:\n",
    "            temp_leave[k] = key\n",
    "            break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "dcd80997",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1: 1,\n",
       " 17: 1,\n",
       " 7: 8,\n",
       " 13: 8,\n",
       " 16: 10,\n",
       " 14: 11,\n",
       " 3: 19,\n",
       " 15: 20,\n",
       " 5: 21,\n",
       " 6: 30,\n",
       " 10: 30,\n",
       " 4: 31,\n",
       " 12: 31,\n",
       " 19: 37,\n",
       " 2: 41,\n",
       " 11: 41,\n",
       " 9: 49,\n",
       " 8: 57,\n",
       " 18: 59,\n",
       " 0: 61,\n",
       " 20: 61}"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temp_leave"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "60771072",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A0002乘坐FA680/17到达PGX\n",
      "A0018乘坐FA680/17到达PGX\n",
      "A0008乘坐FA681/19到达NKX\n",
      "A0014乘坐FA681/19到达NKX\n",
      "A0017乘坐FA812/16到达PDK\n",
      "A0015乘坐FA812/17到达PDK\n",
      "A0004乘坐FA813/20到达NKX\n",
      "A0016乘坐FA854/16到达CTH\n",
      "A0006乘坐FA854/17到达CTH\n",
      "A0007乘坐FA864/16到达PXB\n",
      "A0011乘坐FA864/16到达PXB\n",
      "A0005乘坐FA864/17到达PXB\n",
      "A0013乘坐FA864/17到达PXB\n",
      "A0020乘坐FA865/18到达NKX\n",
      "A0003乘坐FA872/17到达PLM\n",
      "A0012乘坐FA872/17到达PLM\n",
      "A0010乘坐FA873/20到达NKX\n",
      "A0009乘坐FA885/18到达NKX\n",
      "A0019乘坐FA885/20到达NKX\n",
      "A0001乘坐FA889/18到达NKX\n",
      "A0021乘坐FA889/18到达NKX\n"
     ]
    }
   ],
   "source": [
    "for key, value in temp_leave.items():\n",
    "    print(str(data_loader_a2.C_dic[key])+\"乘坐\"+str(data_loader_a2.F_dic[value])+\"到达\"+str(data_loader_a2.AP_dic[data_loader_a2.F_ap_arr_dic[value]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "d3193a42",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 16,\n",
       " 1: 17,\n",
       " 2: 18,\n",
       " 3: 19,\n",
       " 4: 20,\n",
       " 5: 16,\n",
       " 6: 17,\n",
       " 7: 18,\n",
       " 8: 19,\n",
       " 9: 20,\n",
       " 10: 16,\n",
       " 11: 17,\n",
       " 12: 18,\n",
       " 13: 19,\n",
       " 14: 20,\n",
       " 15: 16,\n",
       " 16: 17,\n",
       " 17: 18,\n",
       " 18: 19,\n",
       " 19: 20,\n",
       " 20: 16,\n",
       " 21: 17,\n",
       " 22: 18,\n",
       " 23: 19,\n",
       " 24: 20,\n",
       " 25: 16,\n",
       " 26: 17,\n",
       " 27: 18,\n",
       " 28: 19,\n",
       " 29: 20,\n",
       " 30: 16,\n",
       " 31: 17,\n",
       " 32: 18,\n",
       " 33: 19,\n",
       " 34: 20,\n",
       " 35: 16,\n",
       " 36: 17,\n",
       " 37: 18,\n",
       " 38: 19,\n",
       " 39: 20,\n",
       " 40: 16,\n",
       " 41: 17,\n",
       " 42: 18,\n",
       " 43: 19,\n",
       " 44: 20,\n",
       " 45: 16,\n",
       " 46: 17,\n",
       " 47: 18,\n",
       " 48: 19,\n",
       " 49: 20,\n",
       " 50: 16,\n",
       " 51: 17,\n",
       " 52: 18,\n",
       " 53: 19,\n",
       " 54: 20,\n",
       " 55: 16,\n",
       " 56: 17,\n",
       " 57: 18,\n",
       " 58: 19,\n",
       " 59: 20,\n",
       " 60: 18,\n",
       " 61: 18,\n",
       " 62: 16,\n",
       " 63: 17,\n",
       " 64: 18,\n",
       " 65: 19,\n",
       " 66: 20,\n",
       " 67: 16,\n",
       " 68: 17,\n",
       " 69: 18,\n",
       " 70: 19,\n",
       " 71: 20}"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_loader_a2.leavedate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "id": "3fd1574d",
   "metadata": {},
   "outputs": [],
   "source": [
    "temp_leave_dic = {}\n",
    "MinRest = 2\n",
    "for k in data_loader_a2.C:\n",
    "    for i in data_loader_a2.F:\n",
    "        if k not in temp_leave_dic.keys():\n",
    "            temp_leave_dic[k] = []\n",
    "        if (data_loader_a2.AP_dic[data_loader_a2.F_ap_dpt_dic[i]] == 'NKX') and ((data_loader_a2.leavedate[i] - data_loader_a.leavedate[temp_leave[k]])>MinRest):#不是到达的机场\n",
    "            continue\n",
    "        else:\n",
    "            if k not in temp_leave_dic.keys(): \n",
    "                temp_leave_dic[k] = [i]\n",
    "            else:\n",
    "                temp_leave_dic[k].append(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "a40789a6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 1: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 2: [0,\n",
       "  1,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  11,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  21,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  31,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  41,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  51,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  63,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 3: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 4: [0,\n",
       "  1,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  11,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  21,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  31,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  41,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  51,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  63,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 5: [0,\n",
       "  1,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  11,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  21,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  31,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  41,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  51,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  63,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 6: [0,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 7: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 8: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 9: [0,\n",
       "  1,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  11,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  21,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  31,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  41,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  51,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  63,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 10: [0,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 11: [0,\n",
       "  1,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  11,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  21,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  31,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  41,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  51,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  63,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 12: [0,\n",
       "  1,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  11,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  21,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  31,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  41,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  51,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  63,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 13: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 14: [0,\n",
       "  1,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  11,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  21,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  31,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  41,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  51,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  63,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 15: [0,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 16: [0,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 17: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 18: [0,\n",
       "  1,\n",
       "  5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  10,\n",
       "  11,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  20,\n",
       "  21,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  30,\n",
       "  31,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  40,\n",
       "  41,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  50,\n",
       "  51,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  62,\n",
       "  63,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 19: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71],\n",
       " 20: [5,\n",
       "  6,\n",
       "  7,\n",
       "  8,\n",
       "  9,\n",
       "  15,\n",
       "  16,\n",
       "  17,\n",
       "  18,\n",
       "  19,\n",
       "  25,\n",
       "  26,\n",
       "  27,\n",
       "  28,\n",
       "  29,\n",
       "  35,\n",
       "  36,\n",
       "  37,\n",
       "  38,\n",
       "  39,\n",
       "  45,\n",
       "  46,\n",
       "  47,\n",
       "  48,\n",
       "  49,\n",
       "  55,\n",
       "  56,\n",
       "  57,\n",
       "  58,\n",
       "  59,\n",
       "  61,\n",
       "  67,\n",
       "  68,\n",
       "  69,\n",
       "  70,\n",
       "  71]}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temp_leave_dic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "cb63e0e5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "36"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(temp_leave_dic[3])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "731d0fc1",
   "metadata": {},
   "source": [
    "## 第二阶段"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "600ec15c",
   "metadata": {},
   "source": [
    "### 优化目标①"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "id": "9378eb16",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gurobi Optimizer version 9.1.2 build v9.1.2rc0 (win64)\n",
      "Thread count: 8 physical cores, 16 logical processors, using up to 16 threads\n",
      "Optimize a model with 741282 rows, 449136 columns and 3350595 nonzeros\n",
      "Model fingerprint: 0x18158102\n",
      "Variable types: 0 continuous, 449136 integer (449136 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 1e+06]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+00]\n",
      "  RHS range        [1e+00, 1e+04]\n",
      "Found heuristic solution: objective 0.0000000\n",
      "Presolve removed 718981 rows and 411307 columns (presolve time = 5s) ...\n",
      "Presolve removed 718981 rows and 411307 columns\n",
      "Presolve time: 5.95s\n",
      "Presolved: 22301 rows, 37829 columns, 160692 nonzeros\n",
      "Variable types: 0 continuous, 37829 integer (37829 binary)\n",
      "\n",
      "Deterministic concurrent LP optimizer: primal and dual simplex\n",
      "Showing first log only...\n",
      "\n",
      "\n",
      "Root simplex log...\n",
      "\n",
      "Iteration    Objective       Primal Inf.    Dual Inf.      Time\n",
      "       0    0.0000000e+00   0.000000e+00   1.465586e+02      6s\n",
      "   20568   -2.1848467e+01   0.000000e+00   6.038447e+04     10s\n",
      "   42226   -4.4219527e+01   0.000000e+00   4.780826e+04     15s\n",
      "   63520   -5.8283963e+01   0.000000e+00   1.225473e+06     20s\n",
      "Concurrent spin time: 0.00s\n",
      "\n",
      "Solved with dual simplex\n",
      "\n",
      "Root relaxation: objective -7.200000e+01, 36086 iterations, 16.95 seconds\n",
      "Total elapsed time = 28.46s\n",
      "Total elapsed time = 34.44s\n",
      "Total elapsed time = 35.23s\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0  -72.00000    0  127    0.00000  -72.00000      -     -   36s\n",
      "H    0     0                      -2.0000000  -72.00000  3500%     -   36s\n",
      "H    0     0                     -27.0000000  -72.00000   167%     -   36s\n",
      "H    0     0                     -34.0000000  -72.00000   112%     -   40s\n",
      "H    0     0                     -70.0000000  -72.00000  2.86%     -   40s\n",
      "H    0     0                     -72.0000000  -72.00000  0.00%     -   40s\n",
      "     0     0  -72.00000    0  193  -72.00000  -72.00000  0.00%     -   40s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 7\n",
      "  Cover: 1\n",
      "  MIR: 18\n",
      "\n",
      "Explored 1 nodes (114040 simplex iterations) in 40.39 seconds\n",
      "Thread count was 16 (of 16 available processors)\n",
      "\n",
      "Solution count 6: -72 -70 -34 ... 0\n",
      "No other solutions better than -72\n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective -7.200000000000e+01, best bound -7.200000000000e+01, gap 0.0000%\n"
     ]
    }
   ],
   "source": [
    "MaxTAFB = 14400 / 15 * 5\n",
    "\n",
    "m=gp.Model('m1')\n",
    "\n",
    "z=m.addVars(data_loader_a2.F,vtype=gp.GRB.BINARY,name='z')\n",
    "x_ikdh=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='x_dh')\n",
    "x_ikfo=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='x_fo')\n",
    "x_ikcap=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='x_cap')\n",
    "\n",
    "r_iksta=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='r_iksta')\n",
    "r_jkfin=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='r_jkfin')\n",
    "d_iksta=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='d_iksta')\n",
    "d_jkfin=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='d_jkfin')\n",
    "p_iksta=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='p_iksta')\n",
    "p_jkfin=m.addVars(data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='p_jkfin')\n",
    "\n",
    "y_ijk=m.addVars(data_loader_a2.F,data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='y_ijk')\n",
    "v_ijk=m.addVars(data_loader_a2.F,data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='v_ijk')\n",
    "w_ijk=m.addVars(data_loader_a2.F,data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='w_ijk')\n",
    "u_ijk=m.addVars(data_loader_a2.F,data_loader_a2.F,data_loader_a2.C,vtype=gp.GRB.BINARY,name='u_ijk')\n",
    "\n",
    "# a1=m.addVar(1,vtype=gp.GRB.INTEGER,name='a1')\n",
    "# a2=m.addVar(2,vtype=gp.GRB.INTEGER,name='a2')\n",
    "\n",
    "\n",
    "m.ModelSense=GRB.MINIMIZE\n",
    "\n",
    "m.setObjective(-z.sum())\n",
    "\n",
    "#m.setObjective(x_ikdh.sum())\n",
    "# m.setObjective(gp.quicksum(x_ikfo[i,k] for i in F for k in C2))\n",
    "# m.setObjective(gp.quicksum(gp.quicksum(data_loader_a.DCost[k]*(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) \n",
    "#                                                                - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]))/60\n",
    "#                                                            for k in data_loader_a.C) for t in data_loader_a.Dates ))\n",
    "# m.setObjective(a1-a2)\n",
    "\n",
    "#m.setObjectiveN(-z.sum(),index = 0,weight =0.8)\n",
    "#m.setObjectiveN(x_ikdh.sum(),index=1,weight=0.2)\n",
    "#m.setObjectiveN(gp.quicksum(x_ikfo[i,k] for i in data_loader_a.F for k in data_loader_a.C2),index=2,weight=0.05)\n",
    "\n",
    "\n",
    "M=10000\n",
    "#对X的约束\n",
    "m.addConstrs(x_ikfo[i,k]==0 for i in data_loader_a2.F for k in data_loader_a2.C1 )\n",
    "m.addConstrs(x_ikcap[i,k]==0 for i in data_loader_a2.F for k in data_loader_a2.C3 )\n",
    "m.addConstrs(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]<=1 for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "\n",
    "#对Z的约束\n",
    "m.addConstrs(gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for k in data_loader_a2.C)<=M*(z[i]) for i in data_loader_a2.F)\n",
    "m.addConstrs(x_ikcap.sum(i,'*')== z[i] for i in data_loader_a2.F )\n",
    "m.addConstrs(x_ikfo.sum(i,'*')== z[i] for i in data_loader_a2.F )\n",
    "m.addConstrs(M*z[j]>=gp.quicksum(x_ikcap[j,k]+x_ikfo[j,k]+x_ikdh[j,k] for k in data_loader_a2.C) for j in data_loader_a2.F)\n",
    "\n",
    "#对Y的约束\n",
    "m.addConstrs(y_ijk[i,j,k]==0 for i,j in data_loader_a2.FF for k in data_loader_a2.C)\n",
    "#m.addConstrs(gp.quicksum(y_ijk[i,j,k] for j in F)<=x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in F for k in C)\n",
    "#m.addConstrs(gp.quicksum(y_ijk[j,i,k] for j in F)<=x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in F for k in C)\n",
    "\n",
    "#对roaster周期的约束\n",
    "# m.addConstrs(r_jkfin[j,k]== 0 for j in data_loader_a.nonF_arrive_base[0] for k in data_loader_a.C)\n",
    "m.addConstrs(r_iksta[i,k]== 0 for i in temp_leave_dic[k] for k in data_loader_a2.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(r_iksta[i,k] for i in data_loader_a2.F_leave_base[0] )<=1  for k in data_loader_a2.C)\n",
    "m.addConstrs(gp.quicksum(r_jkfin[j,k] for j in data_loader_a2.F_arrive_base[0] )-gp.quicksum(r_iksta[i,k] for i in data_loader_a2.F_leave_base[0] ) == 0 for k in data_loader_a2.C)\n",
    "\n",
    "#第一问中航班对应周期的约束\n",
    "m.addConstrs(1-(y_ijk.sum(i,'*',k)+r_iksta[i,k]+r_jkfin[i,k])<=M*(1-(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])) for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "m.addConstrs(y_ijk.sum(i,'*',k)+r_jkfin[i,k]-(y_ijk.sum('*',i,k)+r_iksta[i,k]) == 0 for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "\n",
    "m.addConstrs(y_ijk.sum(i,'*',k)+r_jkfin[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]  for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "m.addConstrs(y_ijk.sum('*',i,k)+r_iksta[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]  for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "\n",
    "#第二问\n",
    "#对V的约束\n",
    "m.addConstrs(v_ijk[i,j,k]==0 for i,j in data_loader_a2.FF1 for k in data_loader_a2.C)\n",
    "m.addConstrs(v_ijk[i,j,k] <= y_ijk[i,j,k] for i in data_loader_a2.F for j in data_loader_a.F for k in data_loader_a2.C)\n",
    "\n",
    "\n",
    "#对duty执勤的约束\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a2.FD[t]) - gp.quicksum(d_jkfin[i,k] for i in data_loader_a2.FD[t]) == 0 for i in data_loader_a2.F for k in data_loader_a2.C for t in data_loader_a2.Dates)\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a2.FD[t])   <= gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a2.FD[t]) for i in data_loader_a2.F for k in data_loader_a2.C for t in data_loader_a2.Dates)\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a2.FD[t])*M >= gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a2.FD[t]) for k in data_loader_a2.C for t in data_loader_a2.Dates)\n",
    "\n",
    "#m.addConstrs(d_iksta[i,k] for i in data_loader_a.FD[t]  <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a.FD[t] for k in data_loader_a.C for t in data_loader_a.Dates)\n",
    "\n",
    "#第二问中航班对应执勤，执勤对应周期的约束\n",
    "m.addConstrs((v_ijk.sum(i,'*',k)+ r_jkfin[i,k] ==  d_jkfin[i,k]) for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "m.addConstrs((v_ijk.sum('*',i,k)+ r_iksta[i,k] ==  d_iksta[i,k]) for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "\n",
    "#m.addConstrs((d_jkfin[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])  for i in data_loader_a.F for k in data_loader_a.C)\n",
    "#m.addConstrs((d_iksta[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])  for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "#第二问中其余约束\n",
    "m.addConstrs(gp.quicksum(d_jkfin[i,k]*data_loader_a2.arrivetime[i] for i in data_loader_a2.FD[t]) - gp.quicksum(d_iksta[i,k]*data_loader_a2.leavetime[i] for i in data_loader_a2.FD[t]) <= 720 for k in data_loader_a2.C for t in data_loader_a2.Dates )\n",
    "m.addConstrs(gp.quicksum((x_ikcap[i,k]+x_ikfo[i,k])*(data_loader_a2.leavetime[i]-data_loader_a2.arrivetime[i]) for i in data_loader_a2.FD[t]) <= 600 for k in data_loader_a2.C for t in data_loader_a2.Dates )\n",
    "#m.addConstrs(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) >= 0 for k in data_loader_a.C for t in data_loader_a.Dates )\n",
    "\n",
    "\n",
    "#m.addConstr(z.sum('*')==206)\n",
    "# m.addConstr(gp.quicksum(gp.quicksum(data_loader_a.DCost[k]*(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) \n",
    "#                     - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]))\n",
    "#                 for k in data_loader_a.C) for t in data_loader_a.Dates )==[1324573-100000,1324573+100000])\n",
    "#对执勤时长平衡的约束（辅助目标）\n",
    "# m.addConstrs(a1>=(gp.quicksum(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates) - gp.quicksum(gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates)) for k in data_loader_a.C)\n",
    "# m.addConstrs(a2<=(gp.quicksum(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates) - gp.quicksum(gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates)) for k in data_loader_a.C)\n",
    "         \n",
    "#第三问\n",
    "#对W的约束\n",
    "m.addConstrs(w_ijk[i,j,k]==0 for i,j in data_loader_a2.FF2 for k in data_loader_a2.C)\n",
    "m.addConstrs(w_ijk[i,j,k] <= v_ijk[i,j,k] for i in data_loader_a2.F for j in data_loader_a2.F for k in data_loader_a2.C)\n",
    "\n",
    "\n",
    "\n",
    "#对U的约束\n",
    "m.addConstrs(r_jkfin[i,k] <=gp.quicksum(u_ijk[j,i,k] for j in data_loader_a2.F) for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "m.addConstrs(r_iksta[i,k] <=gp.quicksum(u_ijk[i,j,k] for j in data_loader_a2.F) for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(u_ijk[j,i,k] for j in data_loader_a2.F) <= d_jkfin[i,k] for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k] for j in data_loader_a2.F) <= d_iksta[i,k] for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k] for j in data_loader_a2.F)-(r_iksta[i,k] + gp.quicksum(w_ijk[j,i,k] for j in data_loader_a2.F)) == 0 for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[j,i,k] for j in data_loader_a2.F)-(r_jkfin[i,k] + gp.quicksum(w_ijk[i,j,k] for j in data_loader_a2.F))== 0 for i in data_loader_a2.F for k in data_loader_a2.C)\n",
    "\n",
    "\n",
    "m.addConstrs(u_ijk[i,j,k]*(data_loader_a2.leavedate[j] - data_loader_a2.leavedate[i] )<= 4 for i in data_loader_a2.F for j in data_loader_a2.F for k in data_loader_a2.C)\n",
    "#m.addConstrs(w_ijk[i,j,k]*(data_loader_a.leavedate[j] - data_loader_a.leavedate[i] )>= 2 for i in data_loader_a.F for j in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k]*(data_loader_a2.arrivetime[j] - data_loader_a2.leavetime[i])for i in data_loader_a2.F for j in data_loader_a2.F )<= MaxTAFB for k in data_loader_a2.C)       \n",
    "m.addConstrs(u_ijk[i,j,k]==0 for i,j in data_loader_a2.FF for k in data_loader_a2.C)\n",
    "\n",
    "# m.addConstr(z.sum()==58)\n",
    "\n",
    "m.update()\n",
    "m.optimize()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "id": "2f7c47a7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0: 4540\n",
      "1: 0\n",
      "2: 3100\n",
      "3: 4575\n",
      "4: 4495\n",
      "5: 2320\n",
      "6: 4540\n",
      "7: 3125\n",
      "8: 4580\n",
      "9: 3125\n",
      "10: 1980\n",
      "11: 3135\n",
      "12: 0\n",
      "13: 495\n",
      "14: 0\n",
      "15: 320\n",
      "16: 0\n",
      "17: 4540\n",
      "18: 480\n",
      "19: 4495\n",
      "20: 0\n"
     ]
    }
   ],
   "source": [
    "for k in data_loader_a2.C:\n",
    "    sum1 = 0\n",
    "    for i in data_loader_a2.F:\n",
    "        for j in data_loader_a2.F:\n",
    "            if u_ijk[i,j,k].x > 0.9:\n",
    "                sum1 += data_loader_a2.arrivetime[j] - data_loader_a2.leavetime[i]\n",
    "    print(str(k)+\": \"+str(sum1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "8ba89d3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "loop_dic={'A0003': [2, 1],\n",
    " 'A0004': [2, 1],\n",
    " 'A0001': [1, 2],\n",
    " 'A0013': [2, 1],\n",
    " 'A0021': [4],\n",
    " 'A0015': [4],\n",
    " 'A0008': [4],\n",
    " 'A0019': [2, 1],\n",
    " 'A0002': [1, 2],\n",
    " 'A0009': [4],\n",
    " 'A0020': [4],\n",
    " 'A0010': [4],\n",
    " 'A0005': [4],\n",
    " 'A0006': [4],\n",
    " 'A0018': [4],\n",
    " 'A0012': [1, 2],\n",
    " 'A0011': [4],\n",
    " 'A0017': [4],\n",
    " 'A0007': [4],\n",
    " 'A0014': [4],\n",
    " 'A0016': [4]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "87c7f440",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'A0003': [2, 1, 3],\n",
       " 'A0004': [2, 1, 4],\n",
       " 'A0001': [1, 2, 4],\n",
       " 'A0013': [2, 1],\n",
       " 'A0021': [4],\n",
       " 'A0015': [4],\n",
       " 'A0008': [4, 3],\n",
       " 'A0019': [2, 1, 1, 1],\n",
       " 'A0002': [1, 2],\n",
       " 'A0009': [4, 4],\n",
       " 'A0020': [4, 4],\n",
       " 'A0010': [4, 3],\n",
       " 'A0005': [4, 4],\n",
       " 'A0006': [4, 2, 1],\n",
       " 'A0018': [4, 4],\n",
       " 'A0012': [1, 2, 3],\n",
       " 'A0011': [4, 2, 1],\n",
       " 'A0017': [4],\n",
       " 'A0007': [4, 4],\n",
       " 'A0014': [4, 1, 1],\n",
       " 'A0016': [4, 1]}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "for i in data_loader_a2.F:\n",
    "    for j in data_loader_a2.F:\n",
    "        for k in data_loader_a2.C:\n",
    "            if u_ijk[i,j,k].x>0.9:\n",
    "                if data_loader_a2.C_dic[k] in loop_dic.keys():\n",
    "                    loop_dic[data_loader_a2.C_dic[k]].append(data_loader_a2.leavedate[j]-data_loader_a2.leavedate[i]+1)\n",
    "                else:\n",
    "                    loop_dic[data_loader_a2.C_dic[k]]=[data_loader_a2.leavedate[j]-data_loader_a2.leavedate[i]+1]\n",
    "loop_dic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "909d841d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "16615.0"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum = 0\n",
    "for i in data_loader_a2.F:\n",
    "    for j in data_loader_a2.F:\n",
    "        for k in data_loader_a2.C:\n",
    "                sum+=data_loader_a2.PCost[k]*(u_ijk[i,j,k].x*data_loader_a2.arrivetime[j] - u_ijk[i,j,k].x*data_loader_a2.leavetime[i])/60\n",
    "sum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "id": "7b77db11",
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in data_loader_a2.F:\n",
    "    for k in data_loader_a2.C:\n",
    "        if x_ikcap[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a2.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(1)\n",
    "        if x_ikfo[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a2.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(2)\n",
    "        if x_ikdh[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a2.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "id": "95de501b",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counting times...(0/70)\n",
      "## Loading C\n",
      "## C loaded\n",
      "## Loading AP\n",
      "## AP loaded\n",
      "## Loading Base\n",
      "## Base loaded\n",
      "## Loading F\n",
      "## F loaded\n",
      "## Loading FF\n",
      "## FF loaded\n",
      "## Loading FF1\n",
      "## FF1 loaded\n",
      "## Loading FF2\n",
      "## FF2 loaded\n",
      "Counting times...(0/70)\n"
     ]
    }
   ],
   "source": [
    "data_loader_a3 = DataLoader('data/Data A-Crew.csv', 'data/Data A-Flight.csv')\n",
    "data_loader_a3.dump_data(cropped_date=(21, 25))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "bf5fa2bb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A0001乘坐FA680/21\n",
      "A0018乘坐FA680/21\n",
      "A0007乘坐FA680/22\n",
      "A0003乘坐FA680/23\n",
      "A0019乘坐FA812/21\n",
      "A0009乘坐FA812/22\n",
      "A0008乘坐FA854/23\n",
      "A0010乘坐FA854/23\n",
      "A0004乘坐FA864/22\n",
      "A0012乘坐FA864/23\n",
      "A0005乘坐FA872/21\n",
      "A0014乘坐FA872/21\n",
      "A0020乘坐FA872/22\n",
      "A0006乘坐FA890/23\n",
      "A0011乘坐FA890/23\n",
      "A0016乘坐FA890/24\n"
     ]
    }
   ],
   "source": [
    "for i in data_loader_a3.F:\n",
    "    for k in data_loader_a3.C:\n",
    "        if r_iksta[i,k].x > 0.9:\n",
    "            print(str(data_loader_a3.C_dic[k])+\"乘坐\"+str(data_loader_a3.F_dic[i]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "cb778a5d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_loader_a3.C"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "id": "1d16fdbc",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A0001乘坐FA681/24\n",
      "A0018乘坐FA681/24\n",
      "A0003乘坐FA681/25\n",
      "A0007乘坐FA681/25\n",
      "A0011乘坐FA681/25\n",
      "A0019乘坐FA681/25\n",
      "A0009乘坐FA813/25\n",
      "A0008乘坐FA855/25\n",
      "A0010乘坐FA855/25\n",
      "A0004乘坐FA865/25\n",
      "A0012乘坐FA865/25\n",
      "A0005乘坐FA873/24\n",
      "A0020乘坐FA873/25\n",
      "A0006乘坐FA885/25\n",
      "A0016乘坐FA891/24\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{0: 8,\n",
       " 17: 8,\n",
       " 2: 9,\n",
       " 6: 9,\n",
       " 10: 9,\n",
       " 18: 9,\n",
       " 8: 19,\n",
       " 7: 29,\n",
       " 9: 29,\n",
       " 3: 39,\n",
       " 11: 39,\n",
       " 4: 48,\n",
       " 19: 49,\n",
       " 5: 59,\n",
       " 15: 68}"
      ]
     },
     "execution_count": 102,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temp_leave = {}\n",
    "for i in data_loader_a3.F:\n",
    "    for k in data_loader_a3.C:\n",
    "        if r_jkfin[i,k].x > 0.9:\n",
    "            print(str(data_loader_a3.C_dic[k])+\"乘坐\"+str(data_loader_a3.F_dic[i]))\n",
    "            temp_leave[k] = i\n",
    "temp_leave"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "ea5d0452",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 'NKX', 1: 'PGX', 2: 'PDK', 3: 'CTH', 4: 'PXB', 5: 'PLM', 6: 'XGS'}"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_loader_a3.AP_dic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "e2cce333",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 0,\n",
       " 1: 0,\n",
       " 2: 0,\n",
       " 3: 0,\n",
       " 4: 0,\n",
       " 5: 1,\n",
       " 6: 1,\n",
       " 7: 1,\n",
       " 8: 1,\n",
       " 9: 1,\n",
       " 10: 0,\n",
       " 11: 0,\n",
       " 12: 0,\n",
       " 13: 0,\n",
       " 14: 0,\n",
       " 15: 2,\n",
       " 16: 2,\n",
       " 17: 2,\n",
       " 18: 2,\n",
       " 19: 2,\n",
       " 20: 0,\n",
       " 21: 0,\n",
       " 22: 0,\n",
       " 23: 0,\n",
       " 24: 0,\n",
       " 25: 3,\n",
       " 26: 3,\n",
       " 27: 3,\n",
       " 28: 3,\n",
       " 29: 3,\n",
       " 30: 0,\n",
       " 31: 0,\n",
       " 32: 0,\n",
       " 33: 0,\n",
       " 34: 0,\n",
       " 35: 4,\n",
       " 36: 4,\n",
       " 37: 4,\n",
       " 38: 4,\n",
       " 39: 4,\n",
       " 40: 0,\n",
       " 41: 0,\n",
       " 42: 0,\n",
       " 43: 0,\n",
       " 44: 0,\n",
       " 45: 5,\n",
       " 46: 5,\n",
       " 47: 5,\n",
       " 48: 5,\n",
       " 49: 5,\n",
       " 50: 0,\n",
       " 51: 0,\n",
       " 52: 0,\n",
       " 53: 0,\n",
       " 54: 0,\n",
       " 55: 6,\n",
       " 56: 6,\n",
       " 57: 6,\n",
       " 58: 6,\n",
       " 59: 6,\n",
       " 60: 0,\n",
       " 61: 0,\n",
       " 62: 0,\n",
       " 63: 0,\n",
       " 64: 0,\n",
       " 65: 6,\n",
       " 66: 6,\n",
       " 67: 6,\n",
       " 68: 6,\n",
       " 69: 6}"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_loader_a3.F_ap_dpt_dic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "6ef90a5b",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 21,\n",
       " 1: 22,\n",
       " 2: 23,\n",
       " 3: 24,\n",
       " 4: 25,\n",
       " 5: 21,\n",
       " 6: 22,\n",
       " 7: 23,\n",
       " 8: 24,\n",
       " 9: 25,\n",
       " 10: 21,\n",
       " 11: 22,\n",
       " 12: 23,\n",
       " 13: 24,\n",
       " 14: 25,\n",
       " 15: 21,\n",
       " 16: 22,\n",
       " 17: 23,\n",
       " 18: 24,\n",
       " 19: 25,\n",
       " 20: 21,\n",
       " 21: 22,\n",
       " 22: 23,\n",
       " 23: 24,\n",
       " 24: 25,\n",
       " 25: 21,\n",
       " 26: 22,\n",
       " 27: 23,\n",
       " 28: 24,\n",
       " 29: 25,\n",
       " 30: 21,\n",
       " 31: 22,\n",
       " 32: 23,\n",
       " 33: 24,\n",
       " 34: 25,\n",
       " 35: 21,\n",
       " 36: 22,\n",
       " 37: 23,\n",
       " 38: 24,\n",
       " 39: 25,\n",
       " 40: 21,\n",
       " 41: 22,\n",
       " 42: 23,\n",
       " 43: 24,\n",
       " 44: 25,\n",
       " 45: 21,\n",
       " 46: 22,\n",
       " 47: 23,\n",
       " 48: 24,\n",
       " 49: 25,\n",
       " 50: 21,\n",
       " 51: 22,\n",
       " 52: 23,\n",
       " 53: 24,\n",
       " 54: 25,\n",
       " 55: 21,\n",
       " 56: 22,\n",
       " 57: 23,\n",
       " 58: 24,\n",
       " 59: 25,\n",
       " 60: 21,\n",
       " 61: 22,\n",
       " 62: 23,\n",
       " 63: 24,\n",
       " 64: 25,\n",
       " 65: 21,\n",
       " 66: 22,\n",
       " 67: 23,\n",
       " 68: 24,\n",
       " 69: 25}"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_loader_a3.leavedate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "5da619d4",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 16,\n",
       " 1: 17,\n",
       " 2: 18,\n",
       " 3: 19,\n",
       " 4: 20,\n",
       " 5: 16,\n",
       " 6: 17,\n",
       " 7: 18,\n",
       " 8: 19,\n",
       " 9: 20,\n",
       " 10: 16,\n",
       " 11: 17,\n",
       " 12: 18,\n",
       " 13: 19,\n",
       " 14: 20,\n",
       " 15: 16,\n",
       " 16: 17,\n",
       " 17: 18,\n",
       " 18: 19,\n",
       " 19: 20,\n",
       " 20: 16,\n",
       " 21: 17,\n",
       " 22: 18,\n",
       " 23: 19,\n",
       " 24: 20,\n",
       " 25: 16,\n",
       " 26: 17,\n",
       " 27: 18,\n",
       " 28: 19,\n",
       " 29: 20,\n",
       " 30: 16,\n",
       " 31: 17,\n",
       " 32: 18,\n",
       " 33: 19,\n",
       " 34: 20,\n",
       " 35: 16,\n",
       " 36: 17,\n",
       " 37: 18,\n",
       " 38: 19,\n",
       " 39: 20,\n",
       " 40: 16,\n",
       " 41: 17,\n",
       " 42: 18,\n",
       " 43: 19,\n",
       " 44: 20,\n",
       " 45: 16,\n",
       " 46: 17,\n",
       " 47: 18,\n",
       " 48: 19,\n",
       " 49: 20,\n",
       " 50: 16,\n",
       " 51: 17,\n",
       " 52: 18,\n",
       " 53: 19,\n",
       " 54: 20,\n",
       " 55: 16,\n",
       " 56: 17,\n",
       " 57: 18,\n",
       " 58: 19,\n",
       " 59: 20,\n",
       " 60: 18,\n",
       " 61: 18,\n",
       " 62: 16,\n",
       " 63: 17,\n",
       " 64: 18,\n",
       " 65: 19,\n",
       " 66: 20,\n",
       " 67: 16,\n",
       " 68: 17,\n",
       " 69: 18,\n",
       " 70: 19,\n",
       " 71: 20}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_loader_a2.leavedate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "a0b28208",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 8,\n",
       " 17: 8,\n",
       " 2: 9,\n",
       " 6: 9,\n",
       " 10: 9,\n",
       " 18: 9,\n",
       " 8: 19,\n",
       " 7: 29,\n",
       " 9: 29,\n",
       " 3: 39,\n",
       " 11: 39,\n",
       " 4: 48,\n",
       " 19: 49,\n",
       " 5: 59,\n",
       " 15: 68}"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temp_leave"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "id": "4c937ab0",
   "metadata": {},
   "outputs": [],
   "source": [
    "temp_leave_dic = {}\n",
    "MinRest = 2\n",
    "for k in data_loader_a3.C:\n",
    "    for i in data_loader_a3.F:\n",
    "        if k not in temp_leave.keys():\n",
    "            temp_leave_dic[k] = []\n",
    "            continue\n",
    "        if ((data_loader_a3.AP_dic[data_loader_a3.F_ap_dpt_dic[i]] == 'NKX') and ((data_loader_a3.leavedate[i] - data_loader_a2.leavedate[temp_leave[k]])>MinRest)):#不是到达的机场\n",
    "            continue\n",
    "        else:\n",
    "            if k not in temp_leave_dic.keys(): \n",
    "                temp_leave_dic[k] = [i]\n",
    "            else:\n",
    "                temp_leave_dic[k].append(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7ba865a",
   "metadata": {},
   "source": [
    "## 第三阶段"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78196ee3",
   "metadata": {},
   "source": [
    "### 优化目标①"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "id": "0113b4b8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gurobi Optimizer version 9.1.2 build v9.1.2rc0 (win64)\n",
      "Thread count: 8 physical cores, 16 logical processors, using up to 16 threads\n",
      "Optimize a model with 703633 rows, 424900 columns and 3173485 nonzeros\n",
      "Model fingerprint: 0x98b4bd93\n",
      "Variable types: 0 continuous, 424900 integer (424900 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 1e+06]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+00]\n",
      "  RHS range        [1e+00, 1e+04]\n",
      "Found heuristic solution: objective 0.0000000\n",
      "Presolve removed 675997 rows and 374367 columns\n",
      "Presolve time: 1.93s\n",
      "Presolved: 27636 rows, 50533 columns, 219965 nonzeros\n",
      "Variable types: 0 continuous, 50533 integer (50533 binary)\n",
      "\n",
      "Deterministic concurrent LP optimizer: primal and dual simplex\n",
      "Showing first log only...\n",
      "\n",
      "\n",
      "Root simplex log...\n",
      "\n",
      "Iteration    Objective       Primal Inf.    Dual Inf.      Time\n",
      "   18722   -2.0884164e+01   0.000000e+00   7.532136e+04      5s\n",
      "   38122   -4.2002828e+01   0.000000e+00   2.199945e+05     10s\n",
      "   57422   -5.7765416e+01   0.000000e+00   4.348166e+04     15s\n",
      "   76222   -6.7725955e+01   0.000000e+00   3.446108e+04     20s\n",
      "   85157   -7.0000000e+01   0.000000e+00   0.000000e+00     23s\n",
      "Concurrent spin time: 4.02s\n",
      "\n",
      "Solved with primal simplex\n",
      "\n",
      "Root relaxation: objective -7.000000e+01, 85157 iterations, 24.97 seconds\n",
      "Total elapsed time = 34.63s\n",
      "Total elapsed time = 43.79s\n",
      "Total elapsed time = 45.04s\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0  -70.00000    0  180    0.00000  -70.00000      -     -   46s\n",
      "H    0     0                      -2.0000000  -70.00000  3400%     -   46s\n",
      "H    0     0                     -28.0000000  -70.00000   150%     -   46s\n",
      "H    0     0                     -36.0000000  -70.00000  94.4%     -   49s\n",
      "     0     0  -70.00000    0  200  -36.00000  -70.00000  94.4%     -   49s\n",
      "H    0     0                     -70.0000000  -70.00000  0.00%     -   52s\n",
      "     0     0  -70.00000    0  200  -70.00000  -70.00000  0.00%     -   52s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 3\n",
      "  Cover: 6\n",
      "  Clique: 4\n",
      "  MIR: 12\n",
      "  StrongCG: 2\n",
      "  GUB cover: 7\n",
      "  Zero half: 4\n",
      "  RLT: 5\n",
      "\n",
      "Explored 1 nodes (231395 simplex iterations) in 52.63 seconds\n",
      "Thread count was 16 (of 16 available processors)\n",
      "\n",
      "Solution count 5: -70 -36 -28 ... 0\n",
      "No other solutions better than -70\n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective -7.000000000000e+01, best bound -7.000000000000e+01, gap 0.0000%\n"
     ]
    }
   ],
   "source": [
    "MaxTAFB = 14400 / 15 * 5\n",
    "\n",
    "m=gp.Model('m1')\n",
    "\n",
    "z=m.addVars(data_loader_a3.F,vtype=gp.GRB.BINARY,name='z')\n",
    "x_ikdh=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='x_dh')\n",
    "x_ikfo=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='x_fo')\n",
    "x_ikcap=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='x_cap')\n",
    "\n",
    "r_iksta=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='r_iksta')\n",
    "r_jkfin=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='r_jkfin')\n",
    "d_iksta=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='d_iksta')\n",
    "d_jkfin=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='d_jkfin')\n",
    "p_iksta=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='p_iksta')\n",
    "p_jkfin=m.addVars(data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='p_jkfin')\n",
    "\n",
    "y_ijk=m.addVars(data_loader_a3.F,data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='y_ijk')\n",
    "v_ijk=m.addVars(data_loader_a3.F,data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='v_ijk')\n",
    "w_ijk=m.addVars(data_loader_a3.F,data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='w_ijk')\n",
    "u_ijk=m.addVars(data_loader_a3.F,data_loader_a3.F,data_loader_a3.C,vtype=gp.GRB.BINARY,name='u_ijk')\n",
    "\n",
    "# a1=m.addVar(1,vtype=gp.GRB.INTEGER,name='a1')\n",
    "# a2=m.addVar(2,vtype=gp.GRB.INTEGER,name='a2')\n",
    "\n",
    "\n",
    "m.ModelSense=GRB.MINIMIZE\n",
    "\n",
    "m.setObjective(-z.sum())\n",
    "\n",
    "#m.setObjective(x_ikdh.sum())\n",
    "# m.setObjective(gp.quicksum(x_ikfo[i,k] for i in F for k in C2))\n",
    "# m.setObjective(gp.quicksum(gp.quicksum(data_loader_a.DCost[k]*(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) \n",
    "#                                                                - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]))\n",
    "#                                                            for k in data_loader_a.C) for t in data_loader_a.Dates ))\n",
    "# m.setObjective(a1-a2)\n",
    "\n",
    "#m.setObjectiveN(-z.sum(),index = 0,weight =0.8)\n",
    "#m.setObjectiveN(x_ikdh.sum(),index=1,weight=0.2)\n",
    "#m.setObjectiveN(gp.quicksum(x_ikfo[i,k] for i in data_loader_a.F for k in data_loader_a.C2),index=2,weight=0.05)\n",
    "\n",
    "\n",
    "M=10000\n",
    "#对X的约束\n",
    "m.addConstrs(x_ikfo[i,k]==0 for i in data_loader_a3.F for k in data_loader_a3.C1 )\n",
    "m.addConstrs(x_ikcap[i,k]==0 for i in data_loader_a3.F for k in data_loader_a3.C3 )\n",
    "m.addConstrs(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]<=1 for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "\n",
    "#对Z的约束\n",
    "m.addConstrs(gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for k in data_loader_a3.C)<=M*(z[i]) for i in data_loader_a3.F)\n",
    "m.addConstrs(x_ikcap.sum(i,'*')== z[i] for i in data_loader_a3.F )\n",
    "m.addConstrs(x_ikfo.sum(i,'*')== z[i] for i in data_loader_a3.F )\n",
    "m.addConstrs(M*z[j]>=gp.quicksum(x_ikcap[j,k]+x_ikfo[j,k]+x_ikdh[j,k] for k in data_loader_a3.C) for j in data_loader_a3.F)\n",
    "\n",
    "#对Y的约束\n",
    "m.addConstrs(y_ijk[i,j,k]==0 for i,j in data_loader_a3.FF for k in data_loader_a3.C)\n",
    "#m.addConstrs(gp.quicksum(y_ijk[i,j,k] for j in F)<=x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in F for k in C)\n",
    "#m.addConstrs(gp.quicksum(y_ijk[j,i,k] for j in F)<=x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in F for k in C)\n",
    "\n",
    "#对roaster周期的约束\n",
    "# m.addConstrs(r_jkfin[j,k]== 0 for j in data_loader_a.nonF_arrive_base[0] for k in data_loader_a.C)\n",
    "m.addConstrs(r_iksta[i,k]== 0 for i in temp_leave_dic[k] for k in data_loader_a3.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(r_iksta[i,k] for i in data_loader_a3.F_leave_base[0] )<=1  for k in data_loader_a3.C)\n",
    "m.addConstrs(gp.quicksum(r_jkfin[j,k] for j in data_loader_a3.F_arrive_base[0] )-gp.quicksum(r_iksta[i,k] for i in data_loader_a3.F_leave_base[0] ) == 0 for k in data_loader_a3.C)\n",
    "\n",
    "#第一问中航班对应周期的约束\n",
    "m.addConstrs(1-(y_ijk.sum(i,'*',k)+r_iksta[i,k]+r_jkfin[i,k])<=M*(1-(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])) for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "m.addConstrs(y_ijk.sum(i,'*',k)+r_jkfin[i,k]-(y_ijk.sum('*',i,k)+r_iksta[i,k]) == 0 for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "\n",
    "m.addConstrs(y_ijk.sum(i,'*',k)+r_jkfin[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]  for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "m.addConstrs(y_ijk.sum('*',i,k)+r_iksta[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k]  for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "\n",
    "#第二问\n",
    "#对V的约束\n",
    "m.addConstrs(v_ijk[i,j,k]==0 for i,j in data_loader_a3.FF1 for k in data_loader_a3.C)\n",
    "m.addConstrs(v_ijk[i,j,k] <= y_ijk[i,j,k] for i in data_loader_a3.F for j in data_loader_a.F for k in data_loader_a3.C)\n",
    "\n",
    "\n",
    "#对duty执勤的约束\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a3.FD[t]) - gp.quicksum(d_jkfin[i,k] for i in data_loader_a3.FD[t]) == 0 for i in data_loader_a3.F for k in data_loader_a3.C for t in data_loader_a3.Dates)\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a3.FD[t])   <= gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a3.FD[t]) for i in data_loader_a3.F for k in data_loader_a3.C for t in data_loader_a3.Dates)\n",
    "m.addConstrs(gp.quicksum(d_iksta[i,k] for i in data_loader_a3.FD[t])*M >= gp.quicksum(x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a3.FD[t]) for k in data_loader_a3.C for t in data_loader_a3.Dates)\n",
    "\n",
    "#m.addConstrs(d_iksta[i,k] for i in data_loader_a.FD[t]  <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k] for i in data_loader_a.FD[t] for k in data_loader_a.C for t in data_loader_a.Dates)\n",
    "\n",
    "#第二问中航班对应执勤，执勤对应周期的约束\n",
    "m.addConstrs((v_ijk.sum(i,'*',k)+ r_jkfin[i,k] ==  d_jkfin[i,k]) for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "m.addConstrs((v_ijk.sum('*',i,k)+ r_iksta[i,k] ==  d_iksta[i,k]) for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "\n",
    "#m.addConstrs((d_jkfin[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])  for i in data_loader_a.F for k in data_loader_a.C)\n",
    "#m.addConstrs((d_iksta[i,k] <= x_ikcap[i,k]+x_ikfo[i,k]+x_ikdh[i,k])  for i in data_loader_a.F for k in data_loader_a.C)\n",
    "\n",
    "#第二问中其余约束\n",
    "m.addConstrs(gp.quicksum(d_jkfin[i,k]*data_loader_a3.arrivetime[i] for i in data_loader_a3.FD[t]) - gp.quicksum(d_iksta[i,k]*data_loader_a3.leavetime[i] for i in data_loader_a3.FD[t]) <= 720 for k in data_loader_a3.C for t in data_loader_a3.Dates )\n",
    "m.addConstrs(gp.quicksum((x_ikcap[i,k]+x_ikfo[i,k])*(data_loader_a3.leavetime[i]-data_loader_a3.arrivetime[i]) for i in data_loader_a3.FD[t]) <= 600 for k in data_loader_a3.C for t in data_loader_a3.Dates )\n",
    "#m.addConstrs(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) >= 0 for k in data_loader_a.C for t in data_loader_a.Dates )\n",
    "\n",
    "\n",
    "#m.addConstr(z.sum('*')==206)\n",
    "# m.addConstr(gp.quicksum(gp.quicksum(data_loader_a.DCost[k]*(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) \n",
    "#                     - gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]))\n",
    "#                 for k in data_loader_a.C) for t in data_loader_a.Dates )==[1324573-100000,1324573+100000])\n",
    "#对执勤时长平衡的约束（辅助目标）\n",
    "# m.addConstrs(a1>=(gp.quicksum(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates) - gp.quicksum(gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates)) for k in data_loader_a.C)\n",
    "# m.addConstrs(a2<=(gp.quicksum(gp.quicksum(d_jkfin[i,k]*data_loader_a.arrivetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates) - gp.quicksum(gp.quicksum(d_iksta[i,k]*data_loader_a.leavetime[i] for i in data_loader_a.FD[t]) for t in data_loader_a.Dates)) for k in data_loader_a.C)\n",
    "         \n",
    "#第三问\n",
    "#对W的约束\n",
    "m.addConstrs(w_ijk[i,j,k]==0 for i,j in data_loader_a3.FF2 for k in data_loader_a3.C)\n",
    "m.addConstrs(w_ijk[i,j,k] <= v_ijk[i,j,k] for i in data_loader_a3.F for j in data_loader_a3.F for k in data_loader_a3.C)\n",
    "\n",
    "\n",
    "\n",
    "#对U的约束\n",
    "m.addConstrs(r_jkfin[i,k] <=gp.quicksum(u_ijk[j,i,k] for j in data_loader_a3.F) for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "m.addConstrs(r_iksta[i,k] <=gp.quicksum(u_ijk[i,j,k] for j in data_loader_a3.F) for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(u_ijk[j,i,k] for j in data_loader_a3.F) <= d_jkfin[i,k] for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k] for j in data_loader_a3.F) <= d_iksta[i,k] for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k] for j in data_loader_a3.F)-(r_iksta[i,k] + gp.quicksum(w_ijk[j,i,k] for j in data_loader_a3.F)) == 0 for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[j,i,k] for j in data_loader_a3.F)-(r_jkfin[i,k] + gp.quicksum(w_ijk[i,j,k] for j in data_loader_a3.F))== 0 for i in data_loader_a3.F for k in data_loader_a3.C)\n",
    "\n",
    "\n",
    "m.addConstrs(u_ijk[i,j,k]*(data_loader_a3.leavedate[j] - data_loader_a3.leavedate[i] )<= 4 for i in data_loader_a3.F for j in data_loader_a3.F for k in data_loader_a3.C)\n",
    "#m.addConstrs(w_ijk[i,j,k]*(data_loader_a.leavedate[j] - data_loader_a.leavedate[i] )>= 2 for i in data_loader_a.F for j in data_loader_a.F for k in data_loader_a.C)\n",
    "m.addConstrs(gp.quicksum(u_ijk[i,j,k]*(data_loader_a3.arrivetime[j] - data_loader_a3.leavetime[i])for i in data_loader_a3.F for j in data_loader_a3.F )<= MaxTAFB for k in data_loader_a3.C)       \n",
    "m.addConstrs(u_ijk[i,j,k]==0 for i,j in data_loader_a3.FF for k in data_loader_a3.C)\n",
    "\n",
    "m.update()\n",
    "m.optimize()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f7648e1",
   "metadata": {},
   "source": [
    "# 结果计算与导出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "id": "0f2aa28b",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0: 4455\n",
      "1: 4580\n",
      "2: 2960\n",
      "3: 4735\n",
      "4: 4500\n",
      "5: 4745\n",
      "6: 2615\n",
      "7: 3455\n",
      "8: 3675\n",
      "9: 3895\n",
      "10: 4565\n",
      "11: 4790\n",
      "12: 4510\n",
      "13: 520\n",
      "14: 3085\n",
      "15: 4495\n",
      "16: 1695\n",
      "17: 4700\n",
      "18: 2450\n",
      "19: 4050\n",
      "20: 4500\n"
     ]
    }
   ],
   "source": [
    "for k in data_loader_a3.C:\n",
    "    sum1 = 0\n",
    "    for i in data_loader_a3.F:\n",
    "        for j in data_loader_a3.F:\n",
    "            if u_ijk[i,j,k].x > 0.9:\n",
    "                sum1 += data_loader_a3.arrivetime[j] - data_loader_a3.leavetime[i]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "3ff6d8eb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'A0003': [2, 1, 3, 3],\n",
       " 'A0004': [2, 1, 4, 1, 1, 2, 3],\n",
       " 'A0001': [1, 2, 4, 3, 1, 1, 2],\n",
       " 'A0013': [2, 1, 2, 3],\n",
       " 'A0021': [4, 3, 2],\n",
       " 'A0015': [4, 1, 3],\n",
       " 'A0008': [4, 3, 1, 3],\n",
       " 'A0019': [2, 1, 1, 1, 3],\n",
       " 'A0002': [1, 2, 4],\n",
       " 'A0009': [4, 4, 1, 2, 2],\n",
       " 'A0020': [4, 4, 4],\n",
       " 'A0010': [4, 3, 1, 2, 2, 1],\n",
       " 'A0005': [4, 4, 1, 1, 3, 1, 1, 1],\n",
       " 'A0006': [4, 2, 1, 1, 3, 2, 1],\n",
       " 'A0018': [4, 4, 4, 1],\n",
       " 'A0012': [1, 2, 3, 4, 1],\n",
       " 'A0011': [4, 2, 1, 4],\n",
       " 'A0017': [4, 2],\n",
       " 'A0007': [4, 4, 1, 1, 2, 2, 1, 1],\n",
       " 'A0014': [4, 1, 1, 1, 1],\n",
       " 'A0016': [4, 1, 4]}"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "for i in data_loader_a3.F:\n",
    "    for j in data_loader_a3.F:\n",
    "        for k in data_loader_a3.C:\n",
    "            if u_ijk[i,j,k].x>0.9:\n",
    "                if data_loader_a3.C_dic[k] in loop_dic.keys():\n",
    "                    loop_dic[data_loader_a3.C_dic[k]].append(data_loader_a3.leavedate[j]-data_loader_a3.leavedate[i]+1)\n",
    "                else:\n",
    "                    loop_dic[data_loader_a3.C_dic[k]] = [data_loader_a3.leavedate[j]-data_loader_a3.leavedate[i]+1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "4c37d7e7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "26325.00000000001"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum = 0\n",
    "for i in data_loader_a3.F:\n",
    "    for j in data_loader_a3.F:\n",
    "        for k in data_loader_a3.C:\n",
    "            sum+=data_loader_a3.PCost[k]*(u_ijk[i,j,k].x*data_loader_a3.arrivetime[j] - u_ijk[i,j,k].x*data_loader_a3.leavetime[i])/60"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "a1a1f95a",
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in data_loader_a3.F:\n",
    "    for k in data_loader_a3.C:\n",
    "        if x_ikcap[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a3.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(1)\n",
    "        if x_ikfo[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a3.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(2)\n",
    "        if x_ikdh[i,k].x > 0.9:\n",
    "            results_dic['em_no'].append(k)\n",
    "            for key, value in data_loader.F_dic.items():\n",
    "                if value == data_loader_a3.F_dic[i]:\n",
    "                    results_dic['fl_no'].append(key)\n",
    "                    break\n",
    "            results_dic['cls'].append(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "9a96eead",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1: 190, 2: 105, 3: 70, 4: 135}"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "counter = {1:0,2:0,3:0,4:0}\n",
    "for i in range(5): \n",
    "    for ls in loop_dic.values():\n",
    "        for t in ls:\n",
    "            counter[t] += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "da0b655b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from ResultViewer import RViewer\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "ffc2d721",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>em_no</th>\n",
       "      <th>fl_no</th>\n",
       "      <th>cls</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>8</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>16</td>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>17</td>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>463</th>\n",
       "      <td>17</td>\n",
       "      <td>204</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>464</th>\n",
       "      <td>0</td>\n",
       "      <td>205</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>465</th>\n",
       "      <td>5</td>\n",
       "      <td>205</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>466</th>\n",
       "      <td>6</td>\n",
       "      <td>205</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>467</th>\n",
       "      <td>17</td>\n",
       "      <td>205</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>468 rows × 3 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "     em_no  fl_no  cls\n",
       "0        8      0    1\n",
       "1       16      0    2\n",
       "2        1      1    1\n",
       "3       17      1    2\n",
       "4        1      2    1\n",
       "..     ...    ...  ...\n",
       "463     17    204    3\n",
       "464      0    205    1\n",
       "465      5    205    3\n",
       "466      6    205    2\n",
       "467     17    205    3\n",
       "\n",
       "[468 rows x 3 columns]"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.DataFrame(results_dic)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "b909ecf6",
   "metadata": {},
   "outputs": [],
   "source": [
    "rv = RViewer(data_loader, data_cls='a')\n",
    "rv.load_results_from_df(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "921773b1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>fl_no</th>\n",
       "      <th>dpt_date</th>\n",
       "      <th>dpt_time</th>\n",
       "      <th>dpt_ap</th>\n",
       "      <th>arr_date</th>\n",
       "      <th>arr_time</th>\n",
       "      <th>arr_ap</th>\n",
       "      <th>comp</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "Empty DataFrame\n",
       "Columns: [fl_no, dpt_date, dpt_time, dpt_ap, arr_date, arr_time, arr_ap, comp]\n",
       "Index: []"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_a = rv.get_results_df_a()\n",
    "df_a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "061ce290",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_a.to_csv('results/q3_a_UnconveredFlights.csv', index=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "148d4bf2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>em_no</th>\n",
       "      <th>leg_no</th>\n",
       "      <th>fl_no</th>\n",
       "      <th>dpt_date</th>\n",
       "      <th>dpt_time</th>\n",
       "      <th>dpt_ap</th>\n",
       "      <th>arr_date</th>\n",
       "      <th>arr_time</th>\n",
       "      <th>arr_ap</th>\n",
       "      <th>cls</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>A0001</td>\n",
       "      <td>1</td>\n",
       "      <td>FA884</td>\n",
       "      <td>8/11/2021</td>\n",
       "      <td>11:30</td>\n",
       "      <td>NKX</td>\n",
       "      <td>8/11/2021</td>\n",
       "      <td>13:50</td>\n",
       "      <td>XGS</td>\n",
       "      <td>C</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>A0001</td>\n",
       "      <td>2</td>\n",
       "      <td>FA891</td>\n",
       "      <td>8/12/2021</td>\n",
       "      <td>10:30</td>\n",
       "      <td>XGS</td>\n",
       "      <td>8/12/2021</td>\n",
       "      <td>12:50</td>\n",
       "      <td>NKX</td>\n",
       "      <td>C</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>A0001</td>\n",
       "      <td>3</td>\n",
       "      <td>FA680</td>\n",
       "      <td>8/16/2021</td>\n",
       "      <td>8:00</td>\n",
       "      <td>NKX</td>\n",
       "      <td>8/16/2021</td>\n",
       "      <td>9:30</td>\n",
       "      <td>PGX</td>\n",
       "      <td>C</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>A0001</td>\n",
       "      <td>4</td>\n",
       "      <td>FA681</td>\n",
       "      <td>8/16/2021</td>\n",
       "      <td>10:10</td>\n",
       "      <td>PGX</td>\n",
       "      <td>8/16/2021</td>\n",
       "      <td>11:40</td>\n",
       "      <td>NKX</td>\n",
       "      <td>C</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>A0001</td>\n",
       "      <td>5</td>\n",
       "      <td>FA812</td>\n",
       "      <td>8/16/2021</td>\n",
       "      <td>12:20</td>\n",
       "      <td>NKX</td>\n",
       "      <td>8/16/2021</td>\n",
       "      <td>14:05</td>\n",
       "      <td>PDK</td>\n",
       "      <td>C</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>463</th>\n",
       "      <td>A0021</td>\n",
       "      <td>2</td>\n",
       "      <td>FA891</td>\n",
       "      <td>8/12/2021</td>\n",
       "      <td>10:30</td>\n",
       "      <td>XGS</td>\n",
       "      <td>8/12/2021</td>\n",
       "      <td>12:50</td>\n",
       "      <td>NKX</td>\n",
       "      <td>F</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>464</th>\n",
       "      <td>A0021</td>\n",
       "      <td>3</td>\n",
       "      <td>FA681</td>\n",
       "      <td>8/23/2021</td>\n",
       "      <td>10:10</td>\n",
       "      <td>PGX</td>\n",
       "      <td>8/23/2021</td>\n",
       "      <td>11:40</td>\n",
       "      <td>NKX</td>\n",
       "      <td>F</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>465</th>\n",
       "      <td>A0021</td>\n",
       "      <td>4</td>\n",
       "      <td>FA891</td>\n",
       "      <td>8/23/2021</td>\n",
       "      <td>10:30</td>\n",
       "      <td>XGS</td>\n",
       "      <td>8/23/2021</td>\n",
       "      <td>12:50</td>\n",
       "      <td>NKX</td>\n",
       "      <td>D</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>466</th>\n",
       "      <td>A0021</td>\n",
       "      <td>5</td>\n",
       "      <td>FA884</td>\n",
       "      <td>8/24/2021</td>\n",
       "      <td>11:30</td>\n",
       "      <td>NKX</td>\n",
       "      <td>8/24/2021</td>\n",
       "      <td>13:50</td>\n",
       "      <td>XGS</td>\n",
       "      <td>F</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>467</th>\n",
       "      <td>A0021</td>\n",
       "      <td>6</td>\n",
       "      <td>FA890</td>\n",
       "      <td>8/25/2021</td>\n",
       "      <td>7:30</td>\n",
       "      <td>NKX</td>\n",
       "      <td>8/25/2021</td>\n",
       "      <td>9:50</td>\n",
       "      <td>XGS</td>\n",
       "      <td>F</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>468 rows × 10 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "     em_no  leg_no  fl_no   dpt_date dpt_time dpt_ap   arr_date arr_time  \\\n",
       "0    A0001       1  FA884  8/11/2021    11:30    NKX  8/11/2021    13:50   \n",
       "1    A0001       2  FA891  8/12/2021    10:30    XGS  8/12/2021    12:50   \n",
       "2    A0001       3  FA680  8/16/2021     8:00    NKX  8/16/2021     9:30   \n",
       "3    A0001       4  FA681  8/16/2021    10:10    PGX  8/16/2021    11:40   \n",
       "4    A0001       5  FA812  8/16/2021    12:20    NKX  8/16/2021    14:05   \n",
       "..     ...     ...    ...        ...      ...    ...        ...      ...   \n",
       "463  A0021       2  FA891  8/12/2021    10:30    XGS  8/12/2021    12:50   \n",
       "464  A0021       3  FA681  8/23/2021    10:10    PGX  8/23/2021    11:40   \n",
       "465  A0021       4  FA891  8/23/2021    10:30    XGS  8/23/2021    12:50   \n",
       "466  A0021       5  FA884  8/24/2021    11:30    NKX  8/24/2021    13:50   \n",
       "467  A0021       6  FA890  8/25/2021     7:30    NKX  8/25/2021     9:50   \n",
       "\n",
       "    arr_ap cls  \n",
       "0      XGS   C  \n",
       "1      NKX   C  \n",
       "2      PGX   C  \n",
       "3      NKX   C  \n",
       "4      PDK   C  \n",
       "..     ...  ..  \n",
       "463    NKX   F  \n",
       "464    NKX   F  \n",
       "465    NKX   D  \n",
       "466    XGS   F  \n",
       "467    XGS   F  \n",
       "\n",
       "[468 rows x 10 columns]"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_b = rv.get_results_df_b()\n",
    "df_b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "b0b34be7",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_b.to_csv('results/q3_a_CrewRosters.csv', index=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "eff0afd9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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AADQX5s3b06tdb6bwRSVUrLLLts/Pk/YBwAAANCgBx54ILfddls2bdo0301hmhYvXpwDDjggu+2227TfK+wDAAAAaNBtt92Whz/84dlvv/1SSpnv5jBFtdb87Gc/y2233ZaDDjpo2u8X9gEAAAA0ZvPmzdm0aVP222+/LFok/llo9ttvv9x5553ZvHnztC/p9QMdAAAAAI0ZuUefEX0L08jfbXvutSjaBQAAANhJ3LJk+Zwsd+kd6+ZkuUyfkX0AAAAA9MW73vWuHH744TnssMNy1VVXTfv9a9asyV133bXN9DPOOCM//vGPZ6GFC5+RfQAAAADMuRtvvDEXXXRRrr322tx999055JBD8v3vf39alxqvWbMmQ0NDeeQjH7nV9PPOO292G7uAGdkHAAAAwJy7/PLL85KXvCSLFy/OvvvumzPPPDMf+9jHsmzZsixfvjxveMMbkiSrVq3Kcccdl2OOOSbPec5z8s1vfjPf/OY3MzQ0lBtvvDEvf/nLc9JJJ2217KGhodx6661bXl9zzTU54ogjcvjhh+fMM89MrTVr1qzJ61//+rzgBS/IU57ylLzzne/s5+r3jbAPAAAAgDn3wx/+MPvvv/+W12eccUZuv/32fOhDH8pll12WK664IrfffnuS5PGPf3yuvvrqnHXWWfmTP/mTPPWpT83atWtzyCGH5EMf+lA+8pGPjFtPrTUnn3xyPvjBD+YLX/hCfvSjH+Wf//mfkyRXX311Lrnkknz2s5/Ne97znrld4Xki7AMAAABgzj3ykY/ML37xiy2vX/SiF+UXv/hF/uAP/iCnnXZadtlll9xzzz1JkmXLliVJnvWsZ+WWW26ZVj0//elPs8suu+QJT3hCkuS5z31ubrzxxiTJi1/84uyzzz551KMelfvvv38W1mrHI+wDAAAAYM4de+yxufzyy7N58+b84Ac/yJe//OWsWLEil112Wd73vvel1rql7HXXXZck+fKXv5yDDz54y/SHPexh2bhxY5JsVb7X/vvvn82bN2+5rPfzn/98DjnkkCTJXnvtNQdrtmPxAx0AAAAAzLnjjjsu1113XY488shs2rQpF154YS655JIcdthh2W+//bLPPvvkBz/4QZLkJz/5SY499tjcc889+cAHPrBlGW984xvzute9Lknnl32f/exnb1NPKSUf/OAH86pXvSq11ixbtiwve9nLctFFF/VnRedZGS8FnQuDg4N1eHi4b/UBAAAA7Iweeuih3HzzzTn44IOz6667zndzpmXVqlU58MADc8opp8x3U+bNRH+/Usr6WuvgeO81sg8AAACAHcaqVavmuwkLmnv2AQAAAEAjhH0AAAAA0Igd+jLeW5Ysn3D+0jvW9aklC8tE2802A1ox1rGu9xg30fzxjpNTnT+bZebT6PaNt/6TbZftLdcC23DmNpyzYZtpAysHtjyfbF+H2bC9++x4Rt4/Vv/uNdLXxyvXuy9Mpcx8mutz3o5+TmX+TXV/67UznW9n0303fnvC+Xsc8uQ+tYTxGNkHAAAAAI3YoUf2AQAAADB7Vt+waYZLWDrm1DPKLTNcLrPFyD4AAAAA5tyqVauydOnSDA0NbXk89NBDufHGG7N69eoZLfu8886b0fs3b96cE088MUNDQ3n5y1++ZfpXv/rVLFu2LENDQ1mzZs2W6atXr86NN944ozrnipF9AAAAAPTFaaedlj/6oz/aatohhxySQw45ZEbLPe+883LGGWds9/uHh4dzxx135Jprrtlq+pVXXpnXvva1ed3rXrfV9BUrVmx3XXPNyD4AAAAA5s3atWtzyimnbDXtwAMPzGWXXZZnP/vZufLKK5Mk3/nOd7J8+fI897nPzfOe97zcfffd+cd//McMDQ3lxz/+cYaGhnL22WdPWNdHP/rRLFu2LMuWLcvb3/72JMm5556b3/7t3843vvGNDA0N5X3ve1+S5Pjjj8+FF16Yv/3bv83Q0FBuu+22Lcs55ZRTsnbt2i2vR957+OGH56STTso999yTJDnrrLNy5JFHZtmyZbnuuuu2rO/JJ5+cN7zhDTMOOccyo5F9pZS/SvKbSX6S5NW11jtmpVUAAAAANOfd7373lvDu4osvzgEHHDBu2U9+8pO57rrrsmhRJ7664oorsmzZsrzjHe/Ipz/96dx111155StfmVe+8pU58MADt4RvDzzwQI4//vitlrXPPvtkzZo1+cM//MN89atfzSMe8YgMDQ1l+fLlOfPMM3PSSSdtE+B94hOfyKpVq3LggQduE0aO9prXvCbnnXdenvOc5+SCCy7Il7/85WzcuDHXXXddPv/5z+emm27KqaeeuiXw++hHP5qPfOQjueCCC6a5BSe33WFfKeV5SQ5P8utJhpL8ZZJTZ6dZAAAAALRmrMt4x/PXf/3XW4K+JPnd3/3drFixIscdd1x+9Vd/Neeee+6Y79ttt922Cu1GXH/99Vm6dGkGBgaSJIcffnhuvPHGPOc5z5n+iozyrW99a8tyTj/99NRa8453vCPf+973MjQ0lCTZuHHjlvLHHXdcjjvuuBnXO5aZXMZ7QpJLaq2bk3wmneBvK6WUM0spwyOP3pUCAAAAgPE84hGP2Or1pz71qZx++un55Cc/mT322CMf/vCHt8zbvHlzkqTWOu7yDjrooPzHf/xHfv7zn+ehhx7Ktddem1/7tV+blbY++clPzpe+9KUkyZ/92Z/lne98Z57+9Kfn6KOPztq1a3PFFVfkFa94xbjrNptmchnvw5PcliS11lpK2Wt0gVrruUm2xKyDg4Pjb3EAAAAAGMdTn/rUnH766dlll11Sa93qRzJe97rX5cgjj8z999+f66+/fsz3DwwM5Nxzz80JJ5yQJHnJS16Sww47bFba9v73vz9veMMbkiT7779/Lr744uy111757Gc/m6OOOiobN27Mqaf254LYmYR9v0jSG/DtNsO2AAAAADCHVhy6eEbvv+/Gb2/3e1etWjXm9KGhoS2Xuo649dZbtyn3zGc+M+vWrRtzGStXrszKlSsnbcOJJ56YE088cZvpvff86zVem9esWbPV62c84xn57Gc/u025v/mbv9lm2ljrO5tmchnvtUmOSZJSysFJXKMLAAAAAPNoJmHf5UmOKKWcl+Rfkpw/Ky0CAAAAALbLdl/GW2u9r5RyRJIXJPnnWuu1s9csAAAAAGC6ZnLPvtRa701y6Sy1BQAAAACYgZlcxgsAAAAA7ECEfQAAAADQiFJr7Vtlg4ODdXh4uG/1AQAAAOyMHnroodx88805+OCDs+uuu26ZvuGcDXNS38DKgTlZ7s5qvL9fkpRS1tdaB8d7r5F9AAAAAMy5VatWZenSpVm+fHlOOumkzGRA2KpVq7JmzZpx559yyilZu3btdi9/tKGhodx6662ztry5JOwDAAAAoC9OO+20rFu3LkcffXRe9apXzXdzmiTsAwAAAKCvTjvttHzxi1/MTTfdlKOPPjrLly/Pa17zmtRaU2vN6aefniOOOCLLli3Lxz/+8STJunXr8l//63/Nsccem3Xr1k1ax2c+85kcc8wxeeITn5jPfe5zSZIPf/jDOfzww/Prv/7ree9735skufPOO3PCCSdkaGgoy5cvz2233ZYkueCCC3LooYfmhS98YX7yk5/M0ZaYfYv6WdmDP7ojtyxZvtW0pXdM/sdh6mxfAABgIRn9HWaE7zLQngd//NNs2vOe3Hfjt5MkAw9/eE58/guy5pJ/yFFHHZUXv/jF+fjHP55ly5bliU98Yv7u7/4u//qv/5rzzz8/J5xwQk4//fRcfPHFeeYzn5mhoaEkydlnn52rr756q3re+ta3Jkm+9a1v5dOf/nQuvfTSXHLJJXn605+eN73pTfnGN76Rhz3sYXnyk5+cl73sZfn+97+f3//9388LX/jC/PEf/3E+9KEP5ZRTTsnb3va2fPvb3869996bpUuX9nVbzURfwz4AAAAA2Lx5c36+cWN+/NOf5i1veUuS5K677srw8HCOOOKI3HTTTXn+85+fgYGB3HPPPUmSW2+9NYccckiS5PDDD0+SvPnNb86b3/zmbZb/3ve+N69+9atTSsmjHvWo3H///fnud7+be+65JyeeeGKSZPfdd8/w8HD22GOPXHzxxbnwwgvzwAMPZJ999sn3vve9POlJT8qee+6ZPffcM09+8pPnfqPMEpfxAgAAANBXF37k0hz2a4fmWU97Ri666KKsXbs2Z599dp7ylKfk0ksvTa01V111VV760pduec/jH//4fP3rX0+tNddff/2kdey1115bvV66dGkOOOCAfOpTn8ratWtz2mmnZd99981b3/rWvOhFL8oVV1yRpz71qUmSAw44IN/5zndy33335a677srNN988uxtgDhnZBwAAALCTGFg5MK/1//2lH8rHPvuZ/MqjH5ML/+pt+clPf5rXvOY1ue+++7L33nvnoosuyqMf/eicf/75OfLII/OEJzwhP/zhD1Nrzbve9a6cfPLJGRgYyIMPPjjtuvfbb7+cddZZOfroo3P//ffnWc96Vh796EfnxS9+cc4666y8//3vz5IlS7LvvvvmsY99bN74xjfmsMMOy2Mf+9jsv//+c7A15kaptfatssfsunu9Zt/f2Gqa+zDMLvfsAwAAFhL37IO58dBDD+Xmm2/OwQcfnF133XW+m5MkW+7VN9oehyycS2T7ZaK/Xyllfa11cLz3uowXAAAAABoh7AMAAACARgj7AAAAABpTSkmS9PP2bcyekb/byN9xOvxABwAAAEBjdtlllyxevDg/+9nPst9++21XaDTbNo8TPD700EN9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\n",
      "text/plain": [
       "<Figure size 1600x640 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "rv.draw_ef_gantt(save='results/q3_a.png')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:mim] *",
   "language": "python",
   "name": "conda-env-mim-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
